package com.ruoyi.project.job.position.controller;

import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.job.enterprise.domain.JobEnterprise;
import com.ruoyi.project.job.enterprise.service.IJobEnterpriseService;
import com.ruoyi.project.job.position.domain.JobPosition;
import com.ruoyi.project.job.position.service.IJobPositionService;
import com.ruoyi.project.job.receive.domain.JobReceiveDetail;
import com.ruoyi.project.job.receive.service.IJobReceiveDetailService;
import com.ruoyi.project.job.resume.domain.JobResume;
import com.ruoyi.project.job.resume.service.IJobResumeService;
import com.ruoyi.project.system.dict.service.IDictDataService;
import com.ruoyi.project.system.role.mapper.RoleMapper;
import com.ruoyi.project.system.user.domain.User;
import com.ruoyi.project.system.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 职位Controller
 *
 */
@Controller
@RequestMapping("/job/positionCenter")
public class JobPositionCenterController extends BaseController {
    private String prefix = "job/position";

    @Autowired
    private IJobPositionService jobPositionService;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private IJobEnterpriseService jobEnterpriseService;
    @Autowired
    private IDictDataService dictDataService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IJobResumeService jobResumeService;
    @Autowired
    private IJobReceiveDetailService receiveDetailService;

    @GetMapping()
    public String position()
    {
        return prefix + "/position_center";
    }

    /**
     * 查询职位投递情况列表
     */
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(JobPosition jobPosition)
    {
        Long userId = ShiroUtils.getUserId();
        startPage();
        jobPosition.setUserId(ShiroUtils.getUserId());
        // 发布的职位
        jobPosition.setStatus(1);
        List<JobPosition> list = jobPositionService.selectJobPositionDeliveryList(jobPosition);


        List<JobResume> resumeList = jobResumeService.selectJobResumeList(new JobResume());
        List<Long> userList = resumeList.stream().map(JobResume::getUserId).distinct().collect(Collectors.toList());
        List<JobPosition> itemList = jobPositionService.selectJobPositionDeliveryList(jobPosition);
        List<JobReceiveDetail> scoreDtoList = receiveDetailService.selectJobReceiveDetailList(new JobReceiveDetail());
        Map<Long, Long> resumeMap = new HashMap<>();
        for (JobResume jobResume : resumeList) {
            resumeMap.put(jobResume.getResumeId(), jobResume.getUserId());
        }

        double[][] scoreArr = new double[userList.size()][itemList.size()];
        for (JobReceiveDetail scoreDto : scoreDtoList) {
            Long currentUserId = resumeMap.get(scoreDto.getResumeId());
            Long currentItemId = scoreDto.getPositionId();
            for (int i = 0; i < userList.size(); i++) {
                if (currentUserId.equals(userList.get(i))) {
                    for (int j = 0; j < itemList.size(); j++) {
                        JobPosition item = itemList.get(j);
                        if (currentItemId.equals(item.getPositionId())) {
                            scoreArr[i][j] = 2d;
                            break;
                        }
                    }
                    break;
                }
            }
        }
        System.out.println("打印评分矩阵：");
        for (int i = 0; i < scoreArr.length; i++) {
            for (int j = 0; j < scoreArr[i].length; j++) {
                System.out.print(scoreArr[i][j] + "\t");
            }
            System.out.println();
        }
        // 根据评分矩阵构建相似度矩阵，基于用户协同，所以二维数组的长和宽都是用户数
        double[][] similarScoreArr = new double[userList.size()][userList.size()];
        for (int i = 0; i < userList.size(); i++) {
            for (int j = i; j < userList.size(); j++) {
                if (i == j) {
                    similarScoreArr[i][j] = 1;
                } else {
                    // 应用余弦相似度计算
                    double[] arr1 = scoreArr[i];
                    double[] arr2 = scoreArr[j];
                    double molecule =0;
                    double denominator1 = 0;
                    double denominator2 = 0;
                    for (int k = 0; k < arr1.length; k++) {
                        denominator1 += Math.pow(arr1[k], 2);
                        denominator2 += Math.pow(arr2[k], 2);
                        molecule += arr1[k] * arr2[k];
                    }
                    // 分母
                    double denominator = Math.sqrt(denominator1) * Math.sqrt(denominator2);
                    if (denominator != 0) {
                        double resultScore = molecule / denominator;
                        similarScoreArr[i][j] = resultScore;
                        similarScoreArr[j][i] = resultScore;
                    }
                }
            }
        }
        System.out.println("打印相似度矩阵：");
        for (int i = 0; i < similarScoreArr.length; i++) {
            for (int j = 0; j < similarScoreArr[i].length; j++) {
                System.out.print(similarScoreArr[i][j] + "\t\t");
            }
            System.out.println();
        }
        /*
            接下来就是 相似度矩阵 * 评分矩阵 = 推荐矩阵，
            这个思路就是一个用户对项目的评分是来源于其他那个写与他相似的用户对项目的评分
            相似度越高，分数的影响则越大，这个时候回顾一下以前学的矩阵相乘，就是前一个矩阵的每一行 * 后一个矩阵的每一列
         */
        // 定义推荐矩阵
        double[][] recommendScoreArr = new double[userList.size()][itemList.size()];
        /*
            由于前一个矩阵每一行 * 后一个矩阵每一列算起来比较麻烦，所以把后一个矩阵进行倒置一下，行变列，列变行，
            这样就变成前一个矩阵的每一行 * 后一个矩阵的每一行，比较容易计算和理解
         */
        double[][] invertScoreArr = new double[itemList.size()][userList.size()];
        for (int i = 0; i < scoreArr.length; i++) {
            for (int j = 0; j < scoreArr[i].length; j++) {
                invertScoreArr[j][i] = scoreArr[i][j];
            }
        }
        System.out.println("打印倒置后的评分矩阵：");
        for (int i = 0; i < invertScoreArr.length; i++) {
            for (int j = 0; j < invertScoreArr[i].length; j++) {
                System.out.print(invertScoreArr[i][j] + "\t");
            }
            System.out.println();
        }
        for (int i = 0; i < recommendScoreArr.length; i++) {
            for (int j = 0; j < recommendScoreArr[i].length; j++) {
                double[] arr1 = similarScoreArr[i];
                double[] arr2 = invertScoreArr[j];
                double recommendScore = 0d;
                for (int k = 0; k < arr1.length; k++) {
                    recommendScore += arr1[k] * arr2[k];
                }
                recommendScoreArr[i][j] = recommendScore;
            }
        }
        System.out.println("打印推荐矩阵：");
        for (int i = 0; i < recommendScoreArr.length; i++) {
            for (int j = 0; j < recommendScoreArr[i].length; j++) {
                System.out.print(recommendScoreArr[i][j] + "\t\t");
            }
            System.out.println();
        }
        // 这里得到的矩阵实际上就是每个用户对每个物品的预测评分，按照这个预测评分的高低排序把前三个进行推荐就可以了
        // 首先要根据传入的userId找出想要推荐的那个用户的那一行数据
        int index = 0;
        for (int i = 0; i < userList.size(); i++) {
            if (userList.get(i).equals(userId)) {
                index = i;
                break;
            }
        }
        double[] arr = recommendScoreArr[index];
        List<ItemScoreDto> itemScoreDtoList = new ArrayList<>();
        for (int i = 0; i < itemList.size(); i++) {
            itemScoreDtoList.add(new ItemScoreDto(arr[i], itemList.get(i)));
        }

        // 按预测分数从高到低排序
        itemScoreDtoList.sort((o1, o2) -> o2.getItemScore().compareTo(o1.getItemScore()));
        List<JobPosition> recommendList = new ArrayList<>();
        for (ItemScoreDto itemScoreDto : itemScoreDtoList) {
            recommendList.add(itemScoreDto.getItem());
        }

        // 查询用户是否是游客
        int count = roleMapper.selectRoleKeyCount(ShiroUtils.getUserId());
        if (count > 0) {
            recommendList.stream().forEach(s -> s.setView(false));
        } else {
            recommendList.stream().forEach(s -> s.setView(true));
        }
        return getDataTable(recommendList);
    }

    static class ItemScoreDto {
        private Double itemScore;
        private JobPosition item;

        public ItemScoreDto() {
        }

        public ItemScoreDto(Double itemScore, JobPosition item) {
            this.itemScore = itemScore;
            this.item = item;
        }

        public Double getItemScore() {
            return itemScore;
        }

        public void setItemScore(Double itemScore) {
            this.itemScore = itemScore;
        }

        public JobPosition getItem() {
            return item;
        }

        public void setItem(JobPosition item) {
            this.item = item;
        }
    }

    static class ScoreDto {
        private String userId;
        private String itemId;
        private Double score;

        public ScoreDto() {
        }

        public ScoreDto(String userId, String itemId, Double score) {
            this.userId = userId;
            this.itemId = itemId;
            this.score = score;
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public String getItemId() {
            return itemId;
        }

        public void setItemId(String itemId) {
            this.itemId = itemId;
        }

        public Double getScore() {
            return score;
        }

        public void setScore(Double score) {
            this.score = score;
        }
    }

    /**
     * 选择简历
     */
    @GetMapping("/selectResume/{userId}/{positionId}")
    public String selectUser(@PathVariable("userId") Long userId, @PathVariable("positionId") Long positionId, ModelMap mmap)
    {
        mmap.put("userId", userId);
        mmap.put("positionId", positionId);
        return prefix + "/selectResume";
    }


    /**
     * 查看企业
     */
    @GetMapping("/viewEnterpriseInfo/{enterpriseId}")
    public String viewEnterpriseInfo(@PathVariable("enterpriseId") Long enterpriseId, ModelMap mmap)
    {
        JobEnterprise jobEnterprise = jobEnterpriseService.selectJobEnterpriseById(enterpriseId);
        jobEnterprise.setScaleName(dictDataService.selectDictLabel("job_enterprise_scale", jobEnterprise.getScale().toString()));
        jobEnterprise.setCategoryName(dictDataService.selectDictLabel("job_enterprise_category", jobEnterprise.getCategory().toString()));
        mmap.put("jobEnterprise", jobEnterprise);
        return "job/enterprise/view";
    }
}
